#include "stdafx.h"
#include "ModelClass.h"


CModelClass::CModelClass(void) : m_pVertexBuffer(nullptr), m_pIndexBuffer(nullptr), m_pTexture(nullptr), m_pModel(nullptr), m_nVertexCount(0), m_nIndexCount(0)
{
}


CModelClass::~CModelClass(void)
{
}

bool CModelClass::InitializeBuffers(ID3D11Device* pDevice)
{
	VertexType* pVertices;
	unsigned long* ulIndices;
	D3D11_BUFFER_DESC stVertexBufferDesc;
	D3D11_BUFFER_DESC stIndexBufferDesc;
	D3D11_SUBRESOURCE_DATA stVertexData;
	D3D11_SUBRESOURCE_DATA stIndexData;
	HRESULT hResult;

	//m_nVertexCount = 3;
	//m_nIndexCount = 3;

	pVertices = new VertexType[m_nVertexCount];
	if(pVertices == nullptr)
	{
		DEBUG_OUTPUT("pVertices return nullptr");
		return false;
	}

	ulIndices = new unsigned long[m_nIndexCount];
	if(ulIndices == nullptr)
	{
		DEBUG_OUTPUT("ulIndices return nullptr");
		return false;
	}

	//pVertices[0].d3dPos = D3DXVECTOR3(-1.0f, -1.0f, 0.0f); // Bottom Left
	////pVertices[0].d3dColor = D3DXVECTOR4(1.0f, 0.0f, 0.0f, 1.0f);
	//pVertices[0].d3dTexture = D3DXVECTOR2(0.0f, 1.0f);
	//pVertices[0].d3dNormal = D3DXVECTOR3(0.0f, 0.0f, -1.0f);
	//
	//pVertices[1].d3dPos = D3DXVECTOR3(0.0f, 1.0f, 0.0f); // Top Left
	////pVertices[1].d3dColor = D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f);
	//pVertices[1].d3dTexture = D3DXVECTOR2(0.5f, 0.0f);
	//pVertices[1].d3dNormal = D3DXVECTOR3(0.0f, 0.0f, -1.0f);
	//
	//pVertices[2].d3dPos = D3DXVECTOR3(1.0f, -1.0f, 0.0f); // Top Right
	////pVertices[2].d3dColor = D3DXVECTOR4(0.0f, 0.0f, 1.0f, 1.0f);
	//pVertices[2].d3dTexture = D3DXVECTOR2(1.0f, 1.0f);
	//pVertices[2].d3dNormal = D3DXVECTOR3(0.0f, 0.0f, -1.0f);
	//
	////pVertices[3].d3dPos = D3DXVECTOR3(1.0f, 1.0f, 0.0f); // Top Right
	//////pVertices[3].d3dColor = D3DXVECTOR4(0.0f, 0.0f, 1.0f, 1.0f);
	////pVertices[3].d3dTexture = D3DXVECTOR2(1.0f, 0.0f);
	////
	////pVertices[4].d3dPos = D3DXVECTOR3(1.0f, -1.0f, 0.0f); // Bottom Right
	//////pVertices[4].d3dColor = D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f);
	////pVertices[4].d3dTexture = D3DXVECTOR2(1.0f, 1.0f);
	////
	////pVertices[5].d3dPos = D3DXVECTOR3(-1.0f, -1.0f, 0.0f); // Bottom Left
	//////pVertices[5].d3dColor = D3DXVECTOR4(1.0f, 0.0f, 0.0f, 1.0f);
	////pVertices[5].d3dTexture = D3DXVECTOR2(0.0f, 1.0f);
	//
	//ulIndices[0] = 0; // Bottom Left
	//ulIndices[1] = 1; // Top Right
	//ulIndices[2] = 2; // Bottome Right
	////ulIndices[3] = 3; // Bottome Right
	////ulIndices[4] = 4; // Bottome Right
	////ulIndices[5] = 5; // Bottome Right

	for(int i = 0; i < m_nVertexCount; ++i)
	{
		pVertices[i].d3dPos = D3DXVECTOR3(m_pModel[i].fX, m_pModel[i].fY, m_pModel[i].fZ);
		pVertices[i].d3dTexture = D3DXVECTOR2(m_pModel[i].fU, m_pModel[i].fV);
		pVertices[i].d3dNormal = D3DXVECTOR3(m_pModel[i].fXNorm, m_pModel[i].fYNorm, m_pModel[i].fZNorm);

		ulIndices[i] = i;
	}

	stVertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	stVertexBufferDesc.ByteWidth = sizeof(VertexType) * m_nVertexCount;
	stVertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	stVertexBufferDesc.CPUAccessFlags = 0;
	stVertexBufferDesc.MiscFlags = 0;
	stVertexBufferDesc.StructureByteStride = 0;

	stVertexData.pSysMem = pVertices;
	stVertexData.SysMemPitch = 0;
	stVertexData.SysMemSlicePitch = 0;

	hResult = pDevice->CreateBuffer(&stVertexBufferDesc, &stVertexData, &m_pVertexBuffer);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Faied to create vertex buffer");
		return false;
	}

	stIndexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	stIndexBufferDesc.ByteWidth = sizeof(unsigned long) * m_nIndexCount;
	stIndexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
	stIndexBufferDesc.CPUAccessFlags = 0;
	stIndexBufferDesc.MiscFlags = 0;
	stIndexBufferDesc.StructureByteStride = 0;

	stIndexData.pSysMem = ulIndices;
	stIndexData.SysMemPitch = 0;
	stIndexData.SysMemSlicePitch = 0;

	hResult = pDevice->CreateBuffer(&stIndexBufferDesc, &stIndexData, &m_pIndexBuffer);
	if(FAILED(hResult))
	{
		DEBUG_OUTPUT("Failed to create index buffer");
		return false;
	}

	delete[] pVertices;
	pVertices = nullptr;

	delete[] ulIndices;
	ulIndices = nullptr;

	return true;
}

void CModelClass::ShutDownBuffers()
{
	if(m_pIndexBuffer != nullptr)
	{
		m_pIndexBuffer->Release();
		m_pIndexBuffer = nullptr;
	}

	if(m_pVertexBuffer != nullptr)
	{
		m_pVertexBuffer->Release();
		m_pVertexBuffer = nullptr;
	}
}

void CModelClass::RenderBuffers(ID3D11DeviceContext* pDeviceContext)
{
	unsigned int nStride;
	unsigned int nOffset;

	nStride = sizeof(VertexType);
	nOffset = 0;

	pDeviceContext->IASetVertexBuffers(0, 1, &m_pVertexBuffer, &nStride, &nOffset);
	pDeviceContext->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
	pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}

bool CModelClass::Initialize(ID3D11Device* pDevice, char* cModelFileName, WCHAR* pwszTextureFileName)
{
	bool bResult = false;

	bResult = LoadModel(cModelFileName);
	if(bResult == false)
	{
		DEBUG_OUTPUT("Failed to load model");
		return false;
	}

	bResult = InitializeBuffers(pDevice);
	if(bResult == false)
	{
		DEBUG_OUTPUT("Failed to initialize model class buffers");
		return false;
	}

	bResult = LoadTexture(pDevice, pwszTextureFileName);
	if(bResult == false)
	{
		DEBUG_OUTPUT("Failed to load texture");
		return false;
	}

	return true;
}

void CModelClass::ShutDown()
{
	ReleaseTexture();
	ShutDownBuffers();
	ReleaseModel();
}

void CModelClass::Render(ID3D11DeviceContext* pDeviceContext)
{
	RenderBuffers(pDeviceContext);
}

int CModelClass::GetIndexCount()
{
	return m_nIndexCount;
}

bool CModelClass::LoadTexture(ID3D11Device* pDevice, WCHAR* pwscTextureName)
{
	bool bResult = false;

	m_pTexture = new CTextureClass();
	if(m_pTexture == nullptr)
	{
		DEBUG_OUTPUT("Failed to create texture pointer");
		return false;
	}

	bResult = m_pTexture->Initialize(pDevice, pwscTextureName);
	if(bResult == false)
	{
		DEBUG_OUTPUT("Failed to initialize texture");
		return false;
	}

	return true;
}

void CModelClass::ReleaseTexture()
{
	if(m_pTexture != nullptr)
	{
		m_pTexture->ShutDown();
		delete m_pTexture;
		m_pTexture = nullptr;
	}
}

ID3D11ShaderResourceView* CModelClass::GetTexture()
{
	return m_pTexture->GetTexture();
}


bool CModelClass::LoadModel(char* cFileName)
{
	ifstream fin;
	char cInput;

	fin.open(cFileName);

	if(fin.fail())
	{
		DEBUG_OUTPUT("Failed to open model file");
		return false;
	}

	fin.get(cInput);

	while(cInput != ':')
	{
		fin.get(cInput);
	}

	fin >> m_nVertexCount;

	m_nIndexCount = m_nVertexCount;

	m_pModel = new ModelType[m_nVertexCount];

	if(m_pModel == nullptr)
	{
		DEBUG_OUTPUT("Failed to create new model type");
		return false;
	}

	fin.get(cInput);

	while(cInput != ':')
	{
		fin.get(cInput);
	}

	fin.get(cInput);
	fin.get(cInput);

	for(int i = 0; i < m_nVertexCount; ++i)
	{
		fin >> m_pModel[i].fX >> m_pModel[i].fY >> m_pModel[i].fZ;
		fin >> m_pModel[i].fU >> m_pModel[i].fV;
		fin >> m_pModel[i].fXNorm >> m_pModel[i].fYNorm >> m_pModel[i].fZNorm;
	}

	fin.close();

	return true;
}

void CModelClass::ReleaseModel()
{
	if(m_pModel)
	{
		delete[] m_pModel;
		m_pModel = nullptr;
	}

	return;
}